#ifndef CLOUD_SHAPE
#define CLOUD_SHAPE

#include <UnityShaderVariables.cginc>

#include "HelperFunc.cginc"

sampler2D _MainTex;
uniform sampler2D _CameraDepthTexture;
float4 _CameraDepthTexture_TexelSize;
uniform sampler2D _DownSampleDepth;
uniform sampler2D _DownSampleOnce;
uniform sampler2D _DownSampleTwice;
uniform sampler2D _DownSampleThird;
uniform sampler2D _ColorCloud;

//RayMarching
uniform float _accuracy;

//sampler
sampler3D _index;
sampler3D _data;
sampler3D _noise;
sampler2D _sin;
sampler2D _blur_noise;

//Debug
int _debug_mode;
bool _debug_iteration;
bool _sky_mode;
// bool _enhanced_ST;

//Field
float3 _corner_in;
float3 _corner_out;
float2 near_far;
float _cloud_scale;
float _high_res_scale;

//adjust
float _data_texel; // data_texel
float4 _movement; // x: sinSpeed, y: sinStrength, z: noiseSpeed, w: noiseStrength
float4 _fbm; // xyz: fbm, w:freq
float2 _clip_panel;

// GaussianBlur
float _BlurSize;


float depth_to_tex(const float end_depth, const float t_far, const float ray_length)
{
    // 三个降采样Pass将结果输出到贴图时进行距离数据到16位贴图的转换
    /// end_depth: 结束步进时候的深度
    /// t_far: 当前这条射线与box的远端交点
    /// ray_length: 当前射线的长度
    /// size: 缩放比例，1用于云的计算，1000用于显示深度
    float result;
    if (end_depth < t_far) result = end_depth / ray_length;
    else result = 258000;
    return max(0.0, result / 15);
}


void get_sin(float3 pos, inout float2 r1, inout float2 r2)
{
    //用三个不同缩放比例的uv来采样三角函数贴图，得到高低频两条简谐振动
    //用监测点的xyz转换成纹理坐标
    pos /= _cloud_scale;
    const float sin_offset = _Time.y * _movement.x;
    float2 sample_result1 = float2((0.09325 * sin_offset) + (0.13 * (pos.y + (0.2 * pos.x))), // y-偏x-方向波动
                                   (0.1865 * sin_offset) + (0.065 * ((-pos.z) + (0.2 * pos.y)))); // z+偏y-方向波动
    float2 sample_result2 = float2((0.373 * sin_offset) + (0.0325 * ((-pos.x) + (0.2 * pos.z))), // x+偏z-方向波动
                                   (1.352 * sin_offset) + (pos.y * 0.2)); // y-方向波动
    sample_result1 /= PI * 2 * _fbm.w; //乘1/(PI * 2)，已知周长求半径，后进行sin函数采样
    r1 = tex2Dlod(_sin, float4(sample_result1.x, 1 - sample_result1.y, 0.0, 0.0)).xy;
    sample_result2 /= PI * 2 * _fbm.w;
    r2 = tex2Dlod(_sin, float4(sample_result2.x, 1 - sample_result2.y, 0.0, 0.0)).xy;
}

float sin_noise(const float val)
{
    const float sin_val = sin(val);
    // return sin_val;
    const float stiffness = 2;
    const float height = 0.3;
    return lerp(1 + sin_val, sin_val, clamp(sin_val * stiffness, -height, height));
}

float get_sin_fbm(float3 pos)
{
    pos /= _cloud_scale;
    const float sin_offset = _Time.y * _movement.x;
    const float oc1 = (0.1 * sin_offset + 0.1 * (pos.y + 0.2 * pos.x)) / PI * 2 * _fbm.w; // y-偏x-方向波动     高频  低幅
    const float oc2 = (0.2 * sin_offset + 0.05 * (-pos.z + 0.2 * pos.y)) / PI * 2 * _fbm.w; // z+偏y-方向波动    中频  中幅
    const float oc3 = (0.4 * sin_offset + 0.025 * (-pos.x + 0.2 * pos.z)) / PI * 2 * _fbm.w; // x+偏z-方向波动    低频  高幅
    const float3 fbm_noise = float3(sin_noise(oc1), sin_noise(oc2), sin_noise(oc3));
    return _fbm.x * fbm_noise.x + _fbm.y * fbm_noise.y + _fbm.z * fbm_noise.z;
}


float sample_noise(const float3 sample_point)
{
    const float3 noise_offset = fmod(_Time.y * _movement.z, 64 * _cloud_scale) * _cloud_scale; // fmod 取余
    float3 uv64 = (((sample_point - noise_offset) * 0.5) / 64.0) * 6.0 / _cloud_scale;
    return _movement.w * tex3Dlod(_noise, float4(uv64, 0.0)).x * sqrt(_cloud_scale);
}

float2 march_field(const float3 ray_origin, const float3 ray_dir, const float val_near, const float val_far)
{
    const float3 vec_to_in = _corner_in - ray_origin; // 从相机位置到包围盒两个角点的向量
    const float3 vec_to_out = _corner_out - ray_origin;

    float3 pos_a = min(vec_to_in / ray_dir, vec_to_out / ray_dir); // 射线与包围盒相交位置
    float3 pos_b = max(vec_to_in / ray_dir, vec_to_out / ray_dir);

    const float t_far = min(pos_b.x, min(pos_b.y, pos_b.z));    // 射线到包围盒远端交点距离
    const float t_near = max(pos_a.x, max(pos_a.y, pos_a.z));   // 射线到包围盒近端交点距离

    return float2(max(val_near, t_near), min(val_far, t_far));
}

float distance_field(float3 pos, const float t)
{
    // 云的整体波动
    // float2 r1, r2;
    // get_sin(pos, r1, r2);
    // const float vib = _fbm.x * r1.x + _fbm.y * r1.y + _fbm.z * r2.x;
    // pos.y += _movement.y * vib * 2.0 * _cloud_scale; // 沿着深度流动
    pos.y += _movement.y * get_sin_fbm(pos) * 2.0 * _cloud_scale; // 沿着深度流动


    // float temp = _movement.y * -0.3 * r2.y; // 细节扰动，y方向

    // 体素采样
    pos = (pos - _corner_in) / _high_res_scale; // 16为体积数据和实际云的比
    const float3 pos_int = floor_accuracy(pos, _cloud_scale);
    const float3 uvx = (pos_int + float3(0.5, 0.5, 0.5)) * _high_res_scale.xxx / (_corner_out - _corner_in); //标准化
    const float3 index = tex3Dlod(_index, float4(1 - uvx.x, _sky_mode ? 1 - uvx.y : uvx.y, uvx.z, 0));
    float value;

    //黄色云 index.x == 1.0 边界 
    if (index.y == 1.0)
    {
        value = index.z * _cloud_scale; //继续步进
    }
    else
    {
        const float3 detail = (pos - pos_int) / _cloud_scale;
        float3 uv_offset = 0.1 + detail * 0.8;  // 针对5^3数据块
        float3 data_uv = float3(((index.xy * 255.0) + float2(1 - uv_offset.x, uv_offset.y)) * _data_texel, uv_offset.z);
        const float data = tex3Dlod(_data, float4(data_uv.x, _sky_mode?1 - data_uv.y:data_uv.y, data_uv.z, 0.0)).x;
        value = max(data * 10 - _clip_panel.y, _clip_panel.x - t); // 算出来到云的距离值，不能小于裁剪距离，双线性插值强度
    }
    return value * sqrt(_cloud_scale);
}

float ray_marching(const float3 ray_origin, const float3 ray_dir, const float w, const float2 t_near_far, inout int it_count, const bool down_one)
{
    float t_near = t_near_far.x;
    float t_far = max(t_near, t_near_far.y);
    //******************新光线步进**********************//
    float threshold = -1000000;
    while (t_near < t_far)
    {
        const float3 pos_near = ray_origin + ray_dir * t_near; // 每一次步进之后距离初始距离t_near
        const float value = distance_field(pos_near, t_near); // 计算得到步进的位置到sdf的距离
        it_count += 1; // debug 记录迭代次数
        float condition;
        if (_accuracy >= 0.01) // 小于这个结束条件停止
            condition = t_near * _accuracy / 1000; // 步进得越远，准确率越低，condition越大
        else
            condition = t_near * w;
        const float noise = sample_noise(pos_near);
        const float result = value - noise * saturate(1 / condition * 8); // 到sdf的距离，离得越远noise效果越低
        const float reach_pos = t_near + result; // 初始位置到圆的前部
        if (result >= threshold)
        {
            t_near += result * 1.8; // 这不怕直接加超了吗，激进的向前前进
            threshold = t_near - reach_pos; //  = 0.6 result
            if (result <= condition)
            {
                const float end = max(t_near_far.x, reach_pos - condition); //表示深度 上万
                t_near = end;
                t_far = end; //结束循环
            }
        }
        else
        {
            // 当某一时刻到sdf的距离不到0.6倍的上一次了距离了
            t_near += (-threshold);
            threshold = -1000000;
        }
    }
    return t_far;
}

float ray_marching_standard(const float3 ray_origin, const float3 ray_dir, const float w, const float2 t_near_far, inout int it_count, const bool down_one)
{
    float t_near = t_near_far.x;
    float t_far = max(t_near, t_near_far.y);
    while (t_near < t_far)
    {
        const float3 pos_near = ray_origin + ray_dir * t_near; // 每一次步进之后距离初始距离t_near
        const float value = distance_field(pos_near, t_near); // 计算得到步进的位置到sdf的距离
        it_count += 1; // debug 记录迭代次数
        float condition;
        if (_accuracy >= 0.01) // 小于这个结束条件停止
            condition = t_near * _accuracy / 1000; // 步进得越远，准确率越低，condition越大
        else
            condition = t_near * w;
        const float noise = sample_noise(pos_near);
        const float result = value - noise * saturate(1 / condition * 8); // 到sdf的距离，离得越远noise效果越低
        const float reach_pos = t_near + result; // 初始位置到圆的前部
        if (result <= condition)
        {
            const float end = max(t_near_far.x, reach_pos - condition); //表示深度 上万
            t_near = end;
            t_far = end; //结束循环
        }
        t_near += result;
    }
    return t_far;
}

float ray_marching_shadow(const float3 ray_origin, const float3 ray_dir, const float w, const float2 t_near_far, inout int it_count, const bool down_one)
{
    float t_near = t_near_far.x;
    float t_far = max(t_near, t_near_far.y);
    //******************新光线步进**********************//
    float threshold = -1000000;
    while (t_near < t_far)
    {
        const float3 pos_near = ray_origin + ray_dir * t_near; // 每一次步进之后距离初始距离t_near
        const float value = distance_field(pos_near, t_near); // 计算得到步进的位置到sdf的距离
        it_count += 1; // debug 记录迭代次数
        float condition;
        if (_accuracy >= 0.01) // 小于这个结束条件停止
            condition = t_near * _accuracy / 1000; // 步进得越远，准确率越低，condition越大
        else
            condition = t_near * w;
        // const float noise = sample_noise(pos_near);
        const float result = value;
        // const float result = value - noise * saturate(1 / condition * 8);
        const float reach_pos = t_near + result; // 初始位置到圆的前部
        if (result >= threshold)
        {
            t_near += result * 1.6; // 这不怕直接加超了吗，激进的向前前进
            threshold = t_near - reach_pos; //  = 0.6 result
            if (result <= condition)
            {
                const float end = max(t_near_far.x, reach_pos - condition); //表示深度 上万
                t_near = end;
                t_far = end; //结束循环
            }
        }
        else
        {
            // 当某一时刻到sdf的距离不到0.6倍的上一次了距离了
            t_near += (-threshold);
            threshold = -1000000;
        }
    }
    return t_far;
}

#endif
